package vip.xumy.core.utils;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;

import vip.xumy.core.exception.CoreException;

/**	All rights reserved
 *	author:mengyxu
 *	date:2019年6月26日
 */

public class StringUtil {
	private static final char[] HEX_DIGITS_L = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
			'c', 'd', 'e', 'f' };
	private static final char[] HEX_DIGITS_U = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
			'C', 'D', 'E', 'F' };
	private static final String DEFAULT_ENCODING = "UTF-8";
	public static final String EMPTY_STRING = "";
	private static final String ARGUMENT_PREFIX = "{";
	private static final String ARGUMENT_SUFFIX = "}";
	private static final Pattern COMPRESS_PATTERN = Pattern.compile("(\\r|\\n|\\r\\n)\\s*");

	private StringUtil() {
		// Add a private constructor to hide the implicit public one.
	}

	public static String compress(String src) {
		return COMPRESS_PATTERN.matcher(src).replaceAll(EMPTY_STRING);
	}

	/**
	 * Concatenate all the parameters to one string.
	 * 
	 * @param src
	 * @param args -- random length parameters.
	 * @return
	 */
	public static String concate(String src, String... args) {
		StringBuilder builder = new StringBuilder().append(src);

		if (args != null) {
			for (String arg : args) {
				builder.append(arg);
			}
		}

		return builder.toString();
	}

	public static String splice(String delimiter, String... args) {
		StringBuilder builder = new StringBuilder();

		if (args != null) {
			for (String arg : args) {
				builder.append(arg == null ? "" : arg).append(delimiter);
			}
		}
		String s = builder.toString();
		return s.substring(0, s.lastIndexOf(delimiter));
	}

	public static String toString(String[] array) {
		if (array == null) {
			return null;
		}

		StringBuilder builder = new StringBuilder();

		builder.append("{");
		for (String element : array) {
			builder.append("'").append(element).append("',");
		}

		builder.deleteCharAt(builder.length() - 1).append("}");

		return builder.toString();
	}

	public static boolean isEmpty(String value) {
		return value == null || value.trim().isEmpty();
	}

	public static String md5(String src, boolean lowercase) throws CoreException {
		return md5(src, null, lowercase);
	}

	/**
	 * 32位小写 MD5 编码
	 * 
	 * @param s
	 * @param encoding
	 * @return
	 * @throws RrsException
	 */
	public static String md5(String s, String expectedEncoding, boolean lowercase) throws CoreException {
		String encoding = DEFAULT_ENCODING;

		if (expectedEncoding != null) {
			encoding = expectedEncoding;
		}

		// 用来将字节转换成 16 进制表示的字符
		char[] hexDigits;
		if (lowercase) {
			hexDigits = HEX_DIGITS_L;
		} else {
			hexDigits = HEX_DIGITS_U;
		}

		String result = null;

		if (s != null) {
			try {
				// 返回实现指定摘要算法的 MessageDigest 对象
				MessageDigest md = MessageDigest.getInstance("MD5");

				// 使用encoding编码将originstr字符串编码并保存到source字节数组
				byte[] source = s.getBytes(encoding);

				// 使用指定的 byte 数组更新摘要
				md.update(source);

				// 通过执行诸如填充之类的最终操作完成哈希计算，结果是一个128位的长整数
				byte[] tmp = md.digest();

				// 用16进制数表示需要32位
				char[] ss = new char[32];

				for (int i = 0, j = 0; i < 16; i++) {
					// j表示转换结果中对应的字符位置
					// 从第一个字节开始，对 MD5 的每一个字节
					// 转换成 16 进制字符
					byte b = tmp[i];

					// 取字节中高 4 位的数字转换
					// 无符号右移运算符>>> ，它总是在左边补0
					// 0x代表它后面的是十六进制的数字. f转换成十进制就是15
					ss[j++] = hexDigits[b >>> 4 & 0xf];

					// 取字节中低 4 位的数字转换
					ss[j++] = hexDigits[b & 0xf];
				}
				result = new String(ss);// 结果转换成字符串用于返回
			} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
				// 当请求特定的加密算法而它在该环境中不可用时抛出此异常
				throw new CoreException("md5(String) - s=" + s, e); //$NON-NLS-1$
			}
		}

		return result;
	}

	public static String[] split(String s, String delimiter) {
		return split(s, delimiter, 10);
	}

	public static String[] split(String s, String delimiter, int initCapacity) {
		List<String> list = new ArrayList<>(initCapacity);

		int index = -1;
		int offset = 0;
		s = s.replace("\\N", "");
		while ((index = s.indexOf(delimiter, index + 1)) != -1) {
			String ss = s.substring(offset, index);
			list.add(ss);
			offset = index + 1;
		}
		list.add(s.substring(offset));

		return list.toArray(new String[0]);
	}

	public static String getStringNum(int length) {
		Random r = new Random();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < length; i++) {
			sb.append(r.nextInt(10));
		}
		return sb.toString();
	}
	
	public static String getStringHex(int length) {
		Random r = new Random();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < length; i++) {
			sb.append(HEX_DIGITS_L[r.nextInt(16)]);
		}
		return sb.toString();
	}

	/**
	 * Pack the reminding left space with filler and return a fixed length string.
	 * Return itself if length of source string is larger or equals to the fixed
	 * length. 左补齐
	 * 
	 * @param src
	 * @param filler
	 * @param totalLength
	 * @return
	 */
	public static String lpad(String src, String filler, int totalLength) {
		// Check length
		int len = src.length();

		// Return itself if larger or equals to the totalLength
		if (len >= totalLength) {
			return src;
		}

		// To pack left space with filler.
		StringBuilder builder = new StringBuilder(totalLength);
		for (int i = len; i < totalLength; i++) {
			builder.append(filler);
		}

		// fill the resource string and return it.
		return builder.append(src).toString();
	}

	/**
	 * 
	 * Pack the reminding right space with filler and return a fixed length string.
	 * Return itself if length of source string is larger or equals to the fixed
	 * length. 右补齐
	 * 
	 * @param src
	 * @param filler
	 * @param totalLength
	 * @return
	 */
	public static String rpad(String src, String filler, int totalLength) {
		int len = src.length();
		if (len >= totalLength) {
			return src;
		}
		StringBuilder builder = new StringBuilder(src);
		for (int i = len; i < totalLength; i++) {
			builder.append(filler);
		}
		return builder.toString();
	}

	public static String subString(String str, int length) {
		return str.substring(0, str.length() > length ? length : str.length());
	}

	public static String subString(String str, int start, int length) {
		if (str == null) {
			return null;
		}
		int len = str.length();
		if (len <= start) {
			return null;
		}
		if (len < start + length) {
			return str.substring(start, len - 1);
		}
		return str.substring(start, start + length);
	}
	
	public static String right(String str, int length) {
		if (str == null) {
			return str;
		}
		int len = str.length();
		if (len <= length) {
			return str;
		}
		return str.substring(len - length);
	}

	// 字符串转换unicode
	public static String stringToUnicode(String string) {
		StringBuffer unicode = new StringBuffer();
		for (int i = 0; i < string.length(); i++) {
			char c = string.charAt(i); // 取出每一个字符
			unicode.append("\\u" + Integer.toHexString(c));// 转换为unicode
		}
		return unicode.toString();
	}

	// unicode 转字符串
	public static String unicodeToString(String unicode) {
		StringBuffer string = new StringBuffer();
		String[] hex = unicode.split("\\\\u");
		for (int i = 1; i < hex.length; i++) {
			int data = Integer.parseInt(hex[i], 16);// 转换出每一个代码点
			string.append((char) data);// 追加成string
		}
		return string.toString();
	}

	/**
	 * Inject the arguments into a string and return.
	 * 
	 * @param src
	 * @param args
	 * @return
	 */
	public static String injectJsonStringArgument(String src, String... args) {
		StringBuilder builder = new StringBuilder();

		int start = 0;
		int end = 0;
		int i = 0;
		while ((start = src.indexOf(ARGUMENT_PREFIX + i + ARGUMENT_SUFFIX, end)) >= 0) {
			builder.append(src.substring(end, start));

			end = src.indexOf(ARGUMENT_SUFFIX, start);

			if (end > start) {
				int index = Integer.valueOf(src.substring(start + 1, end));
				builder.append(args[index]);

				// Move to next
				end += 1;
			} else {
				break;
			}
			i++;
		}

		builder.append(src.substring(end));

		return builder.toString();
	}

	public static boolean isNumeric(String value) {
		return isInteger(value) || isDouble(value);
	}

	public static boolean isInteger(String value) {
		try {
			Integer.parseInt(value);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	public static boolean isDouble(String value) {
		boolean flag = false;

		try {
			if (value.contains(".")) {
				flag = Double.isNaN(Double.parseDouble(value));
			}
		} catch (NumberFormatException e) {
			flag = false;
		}

		return flag;
	}

	public static boolean equals(String src, String dest) {
		if (src == null && dest == null) {
			return true;
		}
		return src != null && src.equals(dest);
	}

	public static boolean isEmpty(String... values) {
		for (String value : values) {
			if (isEmpty(value)) {
				return true;
			}
		}
		return false;
	}

	public static boolean isAllEmpty(String... values) {
		for (String value : values) {
			if (!isEmpty(value)) {
				return false;
			}
		}
		return true;
	}

	public static int length(String str) {
		if (isEmpty(str)) {
			return 0;
		}
		return str.length();
	}

	public static boolean isBlank(final CharSequence cs) {
		int strLen;
		if (cs == null || (strLen = cs.length()) == 0) {
			return true;
		}
		for (int i = 0; i < strLen; i++) {
			if (!Character.isWhitespace(cs.charAt(i))) {
				return false;
			}
		}
		return true;
	}

}
